package com.fusion.ui.nodetreemodel;

import com.fusion.core.node.Friend;
import com.fusion.core.node.FriendManager;
import com.fusion.core.node.Node;
import com.fusion.core.node.UntrustedNode;
import com.fusion.ui.UISubsystem;
import com.stendahls.nif.ui.tree.GenericNode;
import com.stendahls.nif.util.EnumerationIteratorConverter;
import com.stendahls.util.TextUtils;


import javax.swing.*;
import javax.swing.tree.TreeNode;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;

/**
 * @author SwethaShivakumar 
 * Project: fusion
 * Date: Mar 19, 2009
 * URL: http://fusionwiki.co.cc
 * Mail Me At: shiva@fusionproject.co.cc
 */
public class NodeTreeNode extends GenericNode {
	private static final long serialVersionUID = 1L;
	private ArrayList<NodeTreeNode> children;
    private NodeTreeNode parent;
    private Node node;
    private UISubsystem ui;
    private FriendManager manager;
    private String dummyString;
    private NodeTreeModel model;

    public NodeTreeNode(String dummyString) {
        this.dummyString = dummyString;
    }

    public NodeTreeNode(Node node, NodeTreeNode parent, UISubsystem ui, NodeTreeModel model) {
        this.node = node;
        this.parent = parent;
        this.manager = ui.getCore().getFriendManager();
        this.ui = ui;
        this.model = model;
        model.nodeAdded(this);
    }

    private void assureChildrenAreLoaded() {
        if (children == null) {
            children = new ArrayList<NodeTreeNode>();
            if (dummyString != null) return;
            if (node == manager.getMe()) {
                for(Friend f : manager.friends()) children.add(new NodeTreeNode(f, this, ui, model));
            } else {
                if (!node.friendsFriendsLoaded()) {
                    children.add(new NodeTreeNode("Loading ..."));
                    manager.getCore().invokeLater( new Runnable() {
                        public void run() {
                            try {
                                manager.loadSubnodesFor(node);
                            } catch(final IOException e) {
                                SwingUtilities.invokeLater(new Runnable() {
                                    public void run() {
                                        reportError(e.toString());
                                    }
                                });
                            }
                        }
                    });
                } else {
                    for(UntrustedNode n : node.friendsFriends()) {
                        if (parent != null && parent.getNode() == n) continue;
                        if (model.get(n) != null) {
                            children.add(new NodeTreeNode("Recursion to "+n.getNickname()));
                        } else {
                            children.add(new NodeTreeNode(n, this, ui, model));
                        }
                    }
                }
            }
        }
    }

    public TreeNode getChildAt(int childIndex) {
        assureChildrenAreLoaded();
        return children.get(childIndex);
    }

    public int getChildCount() {
        assureChildrenAreLoaded();
        return children.size();
    }

    public TreeNode getParent() {
        return parent;
    }

    public int getIndex(TreeNode node) {
        return children.indexOf((NodeTreeNode)node);
    }

    public boolean getAllowsChildren() {
        return true;
    }

    public boolean isLeaf() {
        return dummyString != null;
    }

    public Enumeration<?> children() {
        assureChildrenAreLoaded();
        return EnumerationIteratorConverter.enumeration(children.iterator());
    }

    public Node getNode() {
        return node;
    }

    public String toString() {
        if (dummyString != null) return dummyString;
        return node.getNickname() + (node.isConnected() ? " ("+ TextUtils.formatByteSize(node.getShareSize())+")" : "");
    }

    public void reloadChildren() {
        children = null;
        assureChildrenAreLoaded();
    }

    public Object getIdentifier() {
        if (node == null) return null;
        return node.getGuid();
    }

    public void reportError(String s) {
        children.clear();
        children.add(new NodeTreeNode(s));
        model.nodeStructureChanged(NodeTreeNode.this);
    }
}
